/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = ora_tti_oversion.c                                 */
/*  NOTE      =                                                    */
/*  DATE      = 2014/12/16 by songbb                               */
/*******************************************************************/

#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>

#include "frcomm.h"
#include "frstr.h"
#include "frmem.h"
#include "frlog.h"

#include "conntrack.h"
#include "frct_comm.h"

#include "../ora_core.h"
#include "../comm/ora_comm.h"
#include "../comm/ora_util.h"
#include "ora_ttc_proto.h"
#include "ora_mar_engine.h"
#include "ora_tti_oversion.h"


/*******************************************************************************
*  FUNC     :  解析OVersion包请求
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_sess                           (Oracle私有的session)
*           :  *p_st_ora_packet                     (Oracle数据包)
*  RTN      :  0                                    (FR_SUCC)
*              1                                    (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int ora_tti_oversion_unpack_req(Conntrack *p_st_conn
                                , L7session_ora *p_st_sess
                                , L7_ora_packet *p_st_ora_packet)
{
    short s_tmp = 0;
    char c_rdbmsVersionO2U = 0;
    int i_bufLen = 0;
    char c_retVerLenO2U = 0;
    char c_retVerNumO2U = 0;
    uint64_t uint64_tmp = 0LL;

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) != FR_SUCC) // seqNumber
        goto error;

    if (ora_mar_unmarshalO2U(p_st_sess, p_st_ora_packet, &c_rdbmsVersionO2U) != FR_SUCC) // rdbmsVersionO2U
        goto error;

    if (ora_mar_unmarshalSWORD(p_st_sess, p_st_ora_packet, &i_bufLen) != FR_SUCC) // bufLen
        goto error;

    if (p_st_sess->i_use_special_field == FR_YES && p_st_sess->i_ptr_len == APM_ORA_PTR_LEN_8)
    {
        if (p_st_sess->i_oci_oversion_skip4 == APM_ORA_FLAG_UNSET)
        {
            if (bytebuff_peek_long(p_st_ora_packet->p_st_packet, 4, &uint64_tmp, BYTE_BIG_ENDIAN) != FR_SUCC)
                goto error;
            if (uint64_tmp == 0x00000000)
                p_st_sess->i_oci_oversion_skip4 = FR_YES;
            else
                p_st_sess->i_oci_oversion_skip4 = FR_NO;
        }
        if (p_st_sess->i_oci_oversion_skip4 == FR_YES)
        {
            ORA_PRINT_DBG("skip 4 bytes after bufLen\n");
            if (ora_mar_skip(p_st_ora_packet, 4) != FR_SUCC)
                goto error;
        }
    }

    if (ora_mar_unmarshalO2U(p_st_sess, p_st_ora_packet, &c_retVerLenO2U) != FR_SUCC) // retVerLenO2U
        goto error;

    if (ora_mar_unmarshalO2U(p_st_sess, p_st_ora_packet, &c_retVerNumO2U) != FR_SUCC) // retVerNumO2U
        goto error;

    return FR_SUCC;
error:
    return FR_FAIL;
}


/*******************************************************************************
*  FUNC     :  RPC -> readRPA
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_sess                           (Oracle私有的session)
*           :  *p_st_ora_packet                     (Oracle数据包)
*  RTN      :  0                                    (FR_SUCC)
*              1                                    (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int ora_tti_oversion_read_RPA(Conntrack *p_st_conn
                            , L7session_ora *p_st_sess
                            , L7_ora_packet *p_st_ora_packet)
{
    int i_retVerLen = 0;
    long long ll_retVerNum = 0LL;
    int i_version_number = 0;
    short s_version_number = 0;
    uint64_t uint64_tmp = 0LL;

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_retVerLen) != FR_SUCC) // retVerLen
        goto error;

    // 如果i_CHR_conversion_flags标志未设置，需要先检测该标志
    if (p_st_sess->i_CHR_conversion_flags == APM_ORA_FLAG_UNSET)
    {
        if (ora_mar_check_bufflen(p_st_ora_packet, 6) != FR_SUCC)
            goto error;
        if (bytebuff_peek_long(p_st_ora_packet->p_st_packet, 6, &uint64_tmp, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        // 0x4f7261636c65 -> Oracle
        p_st_sess->i_CHR_conversion_flags = uint64_tmp == 0x4f7261636c65 ? FR_NO : FR_YES;
        ORA_PRINT_DBG("set p_st_sess->i_CHR_conversion_flag = %s\n", p_st_sess->i_CHR_conversion_flags == FR_YES ? "FR_YES" : "FR_NO");
    }

    if (ora_mar_skipCHR(i_retVerLen, p_st_sess, p_st_ora_packet) != FR_SUCC) // rdbmsVersion
        goto error;

    if (ora_mar_unmarshalUB4(p_st_sess, p_st_ora_packet, &ll_retVerNum) != FR_SUCC) // retVerNum
        goto error;

    i_version_number = (int) (i_version_number + (ll_retVerNum >> 24 & 0xFF) * 1000LL);
    i_version_number = (int) (i_version_number + (ll_retVerNum >> 20 & 0xF) * 100LL);
    i_version_number = (int) (i_version_number + (ll_retVerNum >> 12 & 0xF) * 10LL);
    i_version_number = (int) (i_version_number + (ll_retVerNum >> 8 & 0xF));
    s_version_number = (short) i_version_number;

    p_st_sess->s_version_number = s_version_number;
    ORA_PRINT_DBG("p_st_sess->s_version_number:[%d]\n", p_st_sess->s_version_number);

    return FR_SUCC;
error:
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  设置RPC函数指针
*  ARGS     :  *p_st_ora_rpc_recv  (函数指针结构体)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void ora_tti_oversion_set_rpc_func(Ora_rpc_recv *p_st_ora_rpc_recv)
{
    p_st_ora_rpc_recv->read_RPA = &ora_tti_oversion_read_RPA;
    return;
}
